;;; personal-common.el -- preferences and setup for all instances of Emacs

;;;============================================================================
;;; BASIC CONFIGURATION

;; Miscellaneous preference variables
(setq
 auto-save-file-name-transforms `((".*" ,temporary-file-directory t))
 auto-save-list-file-prefix "~/.autosave/save-"
 backup-directory-alist '(("." . "~/.backups"))
 column-number-mode t
 completion-ignore-case t
 confirm-kill-emacs 'y-or-n-p
 default-fill-column 79
 default-input-method "latin-1-postfix"
 default-tab-width 8
 display-time-24hr-format t
 display-time-day-and-date t
 font-lock-maximum-decoration t
 frame-title-format '("%f")
 hourglass-delay 2
 inhibit-default-init t
 inhibit-startup-echo-area-message user-login-name
 inhibit-startup-message t
 kill-whole-line t
 magic-mode-alist '()
 message-signature-separator "^-- *$"
 mouse-wheel-progressive-speed nil
 mouse-yank-at-point t
 read-file-name-completion-ignore-case t
 require-final-newline t
 ring-bell-function (lambda () nil)
 save-abbrevs nil
 scroll-conservatively 20
 scroll-margin 8
 sentence-end "[.?!][]\"')}]*\\($\\|[ \t]\\)[ \t\n]*"
 sentence-end-double-space nil
 speedbar-show-unknown-files t
 speedbar-use-images nil
 use-dialog-box nil
 woman-use-own-frame nil)

;; Unicode/i18n stuff
(prefer-coding-system 'utf-8-unix)
(set-terminal-coding-system 'utf-8)

;; Adding/removing safeties
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)

;;;============================================================================
;;; FUNCTION DEFINITIONS

(defun join-to-next-line ()
  "Append the next line to the line containing point, cleaning up whitespace
as necessary."
  (interactive)
  (join-line -1))

(defun unfill-paragraph (current-point)
  "Unfill the paragraph containing point; i.e. remove all newlines between
the paragraph separator prior to point and the one after it."
  (interactive "d")
  (let ((fill-column (point-max)))
    (mark-paragraph)
    (fill-region (point) (mark))
    (goto-char current-point)))

(defun beginning-of-line-dwim ()
  "Move point to the beginning of the line, unless it is already there,
in which case move point to the first non-whitespace character on the line."
  (interactive)
  (if (bolp)
      (back-to-indentation)
    (beginning-of-line)))

(defun back-to-indentation-dwim ()
  "Move point to the first non-whitespace character on the line, unless it
is already there, in which case move point to the beginning of the line."
  (interactive)
  (if (= (point)
	 (progn (back-to-indentation) (point)))
      (beginning-of-line)))

(defun buffer-beginning-contains (str &optional bound)
  "Search for STR in the first BOUND (default 1,024) characters of the current
buffer. Returns the character offset of the end of the first match, or nil if
no matches are found."
  (interactive)
  (setq bound (or bound 1024))
  (save-excursion
    (goto-char (point-min))
    (search-forward str bound t)))

(defun push-to-left (start end)
  "Push all text within the active region to the left margin, i.e. unindent
each line back to the 0th column."
  (interactive "r")
  (let ((deactivate-mark))
    (indent-rigidly start end (* -1 (point-max)))))

(defun autocreate-buffer-directory ()
  "If the directory where this buffer is to be saved does not yet exist,
create it."
  (let ((dir (file-name-directory buffer-file-name)))
    (or (file-exists-p dir)
        (make-directory dir t))))

(add-hook 'before-save-hook 'autocreate-buffer-directory)

(when (executable-find "iconv")
  (defun convert-to-ascii (start end)
    ;; Would be nice not to have "utf-8" hard-coded in here, but to use the
    ;; actual buffer encoding is. However, buffer-file-coding-system does not
    ;; really map to the encoding names that iconv wants.
    ;;
    ;; Would be REALLY nice not to have to rely on an external utility that may
    ;; or may not be installed. Not sure how to get Emacs to do
    ;; transliteration, though.
    "Use `iconv' to convert the active region from UTF-8 encoding to US-ASCII,
stripping accents etc. as appropriate."
    (interactive "r")
    (save-excursion
      (shell-command-on-region
       start end "iconv -f utf-8 -t us-ascii//translit" nil t))))

;;;============================================================================
;;; MISCELLANEOUS MINOR MODES

;; Minor modes we DO want
(delete-selection-mode t)
(global-font-lock-mode t)
(transient-mark-mode t)

;; Use ido-mode if available
(when (fboundp 'ido-mode)
  (setq ido-enable-tramp-completion nil
        ido-confirm-unique-completion t
        ido-show-dot-for-dired t)
  (ido-mode t)
  ;; Inject my hackery into ido-mode...
  (load-library "ido-monkeypatch"))

;; Minor modes we DON'T want
(menu-bar-mode -1)

;; Minor mode and buffer-local variable setup for all buffers corresponding to
;; actual files (i.e. not "*Buffer List*" et al.)
(add-hook 'find-file-hook
          (lambda ()
            (show-paren-mode t)
            (setq indent-tabs-mode nil
                  indicate-empty-lines t
                  show-trailing-whitespace t
                  truncate-lines t)))

;;;============================================================================
;;; UNICODE INPUT

(setq unicode-character-list-file (locate-library "unichars"))

(autoload 'unicode-character-insert "xmlunicode"
  "Insert a Unicode character referenced by Unicode character name." t)
(autoload 'iso8879-character-insert "xmlunicode"
  "Insert a Unicode character referenced by ISO-8879 entity name." t)
(autoload 'unicode-character-shortcut-insert "xmlunicode"
  "Insert a Unicode character referenced by a two-character shortcut." t)

(autoload 'unicode-smart-single-quote "xmlunicode")
(autoload 'unicode-smart-double-quote "xmlunicode")
(autoload 'unicode-smart-hyphen "xmlunicode")
(autoload 'unicode-smart-period "xmlunicode")

(defvar smart-punctuation-map (make-sparse-keymap)
  "Keymap for `smart-punctuation-mode' overriding certain punctuation keys
with \"intelligent\" versions and providing keybindings for entering
arbitrary Unicode punctuation characters.")

(define-key smart-punctuation-map (kbd "\"") 'unicode-smart-double-quote)
(define-key smart-punctuation-map (kbd "'") 'unicode-smart-single-quote)
(define-key smart-punctuation-map (kbd "-") 'unicode-smart-hyphen)
(define-key smart-punctuation-map (kbd ".") 'unicode-smart-period)
(define-key smart-punctuation-map (kbd "C-c u") 'unicode-character-insert)
(define-key smart-punctuation-map (kbd "C-c i") 'iso8879-character-insert)

(define-minor-mode smart-punctuation-mode
  "Minor mode allowing easier keyboard entry of proper Unicode punctuation."
  :init-value nil
  :lighter " SmartPn"
  :keymap smart-punctuation-map)

;; Provide a keybinding for toggling smart-punctuation-mode in text-mode (and
;; modes that inherit from it)
(define-key text-mode-map (kbd "C-c p") 'smart-punctuation-mode)

;;;============================================================================
;;; RECENTLY OPENED FILE MENU

;; Rather than loading recentf-mode on startup, we load it either when we first
;; open a file or when we invoke recentf-open-files.

(setq recentf-max-menu-items 24)
(define-key global-map (kbd "C-x M-f")
  #'(lambda ()
      "Load `recentf-mode' and immediately invoke `recentf-open-files'."
      (interactive)
      (recentf-mode 1)
      (recentf-open-files)))

(add-hook 'find-file-hook (lambda () (recentf-mode 1)))
(eval-after-load "recentf"
  (add-hook 'recentf-load-hook
            (lambda ()
              ;; Don't need the "bootstrap" function defined above anymore
              (define-key global-map (kbd "C-x M-f") 'recentf-open-files))))

;;;============================================================================
;;; HIPPIE EXPAND

(autoload 'hippie-expand "hippie-exp" "Hippie-expand library" t)
(setq hippie-expand-try-functions-list
      '(try-expand-all-abbrevs
        try-expand-dabbrev
        try-expand-dabbrev-all-buffers
        try-expand-dabbrev-from-kill
        try-complete-file-name-partially
        try-complete-file-name
        try-complete-lisp-symbol-partially
        try-complete-lisp-symbol))

;;;============================================================================
;;; YASNIPPET

(add-to-list 'load-path (concat shared-lisp-dir "/yasnippet") t)

;; To keep Emacs' startup quick, require this library only when a file is first
;; loaded (subsequent calls to `require' will not load the library again).
(add-hook 'find-file-hook
          (lambda () (require 'yasnippet nil t)))

(eval-after-load
    "yasnippet"
  '(progn
     (setq
      yas/extra-mode-hooks '(javascript-mode-hook sgml-mode-hook xml-mode-hook)
      ;; Don't need a very easy key combo for this since we're going to hook
      ;; yasnippet into hippie-expand
      yas/trigger-key (kbd "C-M-y")
      yas/use-menu nil)

     (setq
      hippie-expand-try-functions-list
      (cons 'yas/hippie-try-expand hippie-expand-try-functions-list))

     (yas/initialize)
     (yas/load-directory (concat shared-lisp-dir "/yasnippet/snippets"))

     ;; Reindent all lines of a snippet after insertion...
     (add-hook 'yas/after-exit-snippet-hook
               (lambda ()
                 (save-excursion
                   (indent-region yas/snippet-beg yas/snippet-end nil))
                 (indent-according-to-mode)))))

;;;============================================================================
;;; KEYBINDINGS

;; I find myself wanting to do hippie-expand much more frequently than I want
;; to type a backtick into a buffer
(define-key global-map (kbd "`") 'hippie-expand)

;; Don't need to minimize/suspend Emacs very often, certainly not nearly as
;; often as I need to use undo.
(define-key global-map (kbd "C-z") 'undo)

;; Override default `move-beginning-of-line' keybinding with DWIM version
(define-key global-map (kbd "C-a") 'beginning-of-line-dwim)

;; This is set by default to `facemenu-keymap', which is truly pointless. The
;; autoload for `find-file-in-project' is defined later on.
(define-key global-map (kbd "M-o") 'find-file-in-project)

;; The rest of these keybindings are either already free or attached by
;; default to functions I rarely or never use
(define-key global-map (kbd "M-g")         'goto-line)
(define-key global-map (kbd "M-'")         'expand-abbrev)
(define-key global-map (kbd "M-#")         'calc)
(define-key global-map (kbd "M-Q")         'unfill-paragraph)
(define-key global-map (kbd "M-j")         'join-to-next-line)
(define-key global-map (kbd "M-=")         'align-regexp)
(define-key global-map (kbd "M-+")         'count-lines-region)
(define-key global-map (kbd "C-c m")       'magit-status)
(define-key global-map (kbd "C-c w")       'delete-trailing-whitespace)
(define-key global-map (kbd "C-c \\")      'toggle-truncate-lines)
(define-key global-map (kbd "C-c q")       'query-replace-string)
(define-key global-map (kbd "C-c M-q")     'query-replace-regexp)
(define-key global-map (kbd "C-c r")       'replace-string)
(define-key global-map (kbd "C-c M-r")     'replace-regexp)
(define-key global-map (kbd "C-c <")       'push-to-left)
(define-key global-map (kbd "C-c 0")       'col-highlight-flash)
(define-key global-map (kbd "C-c C-x C-f") 'find-file-at-point)

(define-key global-map (kbd "<f1>")      'switch-to-buffer)
(define-key global-map (kbd "ESC <f1>")  'kill-buffer)
(define-key global-map (kbd "<f2>")      'buffer-menu)
(define-key global-map (kbd "<f3>")      'start-kbd-macro)
(define-key global-map (kbd "ESC <f3>")  'end-kbd-macro)
(define-key global-map (kbd "<f4>")      'call-last-kbd-macro)
(define-key global-map (kbd "<f5>")      'occur)
(define-key global-map (kbd "ESC <f5>")  'grep)
(define-key global-map (kbd "<f6>")      'string-rectangle)
(define-key global-map (kbd "<f7>")      'query-replace)
(define-key global-map (kbd "ESC <f7>")  'replace-string)
(define-key global-map (kbd "<f8>")      'query-replace-regexp)
(define-key global-map (kbd "ESC <f8>")  'replace-regexp)

;; These might only work in GUI Emacs, but it shouldn't hurt to bind the keys
;; in console Emacs as well. Some terminal emulators might even support them.
(define-key global-map (kbd "<C-tab>")     'other-window)
(define-key global-map (kbd "<C-S-tab>")   'other-frame)

;;;============================================================================
;;; DIRED

(add-hook 'dired-load-hook
  (lambda ()
    (define-key dired-mode-map (kbd "C-c C-f") 'find-name-dired)
    (define-key dired-mode-map (kbd "C-c C-g") 'grep-find)))

;;;============================================================================
;;; GREP

(fset 'grpe 'grep)
(eval-after-load
    "grep"
  '(progn
     (setq grep-command
           (if (executable-find "ack")
               "ack -Hki --nogroup --nocolor "
             "grep -inr "))))

;;;============================================================================
;;; PYTHON

(add-to-list 'load-path (concat shared-lisp-dir "/python") t)
(autoload 'python-mode "python-mode" "Major mode for Python files." t)
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-to-list 'interpreter-mode-alist '("python" . python-mode))
(setq
 py-install-directory (concat shared-lisp-dir "/python"))

;;;============================================================================
;;; C (and derived modes)

(c-add-style "k&r-modified"
             '("k&r"
               (c-basic-offset . 4)
               (c-offsets-alist . ((case-label . +)
                                   (arglist-close . 0)
                                   (defun-open . 0)
                                   (inline-open . 0)))
               (c-hanging-braces-alist
                (substatement-open after))))

(add-hook
 'c-mode-common-hook
 (lambda ()
   (c-set-style "k&r-modified")
   ;; Activate c-subword-mode if available (in Emacs 22.1 and up)
   (when (fboundp 'c-subword-mode)
     (c-subword-mode))))

;;;============================================================================
;;; JAVASCRIPT/COFFEESCRIPT

;; Config for js.el packaged with Emacs
(setq
 js-indent-level 2)

;; Config for enhanced js2-mode
(autoload 'js2-mode
  "js2-mode" "Steve Yegge's major mode for JavaScript files." t)
(setq
 js2-allow-keywords-as-property-names nil
 js2-basic-offset 2
 js2-enter-indents-newline nil
 js2-mirror-mode nil
 js2-strict-inconsistent-return-warning nil)

(add-to-list 'auto-mode-alist '("\\.json\\'" . js-mode))
(add-to-list 'auto-mode-alist '("\\.js\\.erb\\'" . js-mode))

;; Config for CoffeeScript
(autoload 'coffee-mode
  "coffee-mode" "Major mode for editing CoffeeScript files." t)
(add-to-list 'auto-mode-alist '("\\.coffee\\'" . coffee-mode))
(add-to-list 'auto-mode-alist '("\\.coffee\\.erb\\'" . coffee-mode))
(setq
 coffee-tab-width 2)
(eval-after-load
    "coffee-mode"
  '(progn
     ;; Unbinding <RET> in this keymap because of the mode's asinine behavior
     ;; when hitting <RET> with point on column zero: newline gets inserted,
     ;; and the line with point gets DOUBLE-INDENTED! FFFFFFFUUUUUUUUUUUU
     (define-key coffee-mode-map (kbd "C-m") nil)))

;;;============================================================================
;;; PHP

(add-to-list 'load-path (concat shared-lisp-dir "/php") t)
(autoload 'php-mode "php-mode" "Major mode for PHP files." t)
(add-to-list 'auto-mode-alist '("\\.php\\'" . php-mode))
(add-to-list 'auto-mode-alist '("\\.inc\\'" . php-mode))

(setq php-completion-file (concat shared-lisp-dir "/php/php-builtins.txt")
      php-file-patterns nil)

(eval-after-load
    "php-mode"
  '(progn
     ;; Take over the keybinding for dabbrev-expand since we already have
     ;; hippie-expand on backtick
     (define-key php-mode-map (kbd "M-/") 'php-complete-function)))

;;;============================================================================
;;; CSS

(autoload 'css-mode "css-mode" "Major mode for CSS files." t)
(add-to-list 'auto-mode-alist '("\\.css\\'" . css-mode))

(setq
 css-tab-mode 'indent
 css-indent-offset 2)

;;;============================================================================
;;; (X)HTML

(add-to-list 'load-path (concat shared-lisp-dir "/psgml") t)

;; Sadly, PSGML does not really play nicely with Emacs 24.
(when (<= emacs-major-version 23)
  (autoload 'sgml-mode "psgml" "Major mode for HTML/SGML files." t)
  (autoload 'xml-mode  "psgml" "Major mode for XHTML/XML files." t)
  (add-to-list 'auto-mode-alist '("\\.html\\'" . sgml-mode))
  (add-to-list 'auto-mode-alist '("\\.html.erb\\'" . sgml-mode))
  (autoload 'xxml-mode-routine "xxml")
  (add-hook 'sgml-mode-hook 'xxml-mode-routine)
  (add-hook 'xml-mode-hook 'xxml-mode-routine))

(setq
 sgml-files-dir (concat shared-lisp-dir "/psgml/dtd")
 sgml-catalog-files (list (concat sgml-files-dir "/catalog"))
 sgml-ecat-files (list (concat sgml-files-dir "/ecat"))
 sgml-ignore-undefined-elements nil
 sgml-auto-insert-required-elements t
 sgml-insert-missing-element-comment nil
 sgml-validate-command "onsgmls -s %s %s")

(setq
 sgml-custom-dtd
 '(("HTML 4.01 Transitional"
    "<!DOCTYPE HTML PUBLIC \
\"-//W3C//DTD HTML 4.01 Transitional//EN\" \
\"http://www.w3.org/TR/html4/loose.dtd\">\n")
   ("HTML 4.01 Strict"
    "<!DOCTYPE HTML PUBLIC \
\"-//W3C//DTD HTML 4.01//EN\" \
\"http://www.w3.org/TR/html4/strict.dtd\">\n")
   ("XHTML 1.0 Transitional"
    "<!DOCTYPE html PUBLIC \
\"-//W3C//DTD XHTML 1.0 Transitional//EN\" \
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
   ("XHTML 1.0 Strict"
    "<!DOCTYPE html PUBLIC \
\"-//W3C//DTD XHTML 1.0 Strict//EN\" \
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n")))

(defun sgml-set-parent-document ()
  "Set `sgml-parent-document' to a skeleton HTML 4.01 Transitional document
so that HTML fragments can be edited properly with PSGML."
  (interactive)
  (setq sgml-parent-document
        (list (concat shared-lisp-dir "/psgml/parent.html")
              "html" "body" '("div"))))

(add-hook
 'sgml-mode-hook
 (lambda ()
   "If the buffer appears to contain markup but no doctype declaration, run
`sgml-set-parent-document' to treat it as HTML 4.01 Transitional."
   (if (and (buffer-beginning-contains "<")
            (not (buffer-beginning-contains "<!DOCTYPE")))
       (sgml-set-parent-document))))

(eval-after-load
    "psgml"
  '(progn
     (define-key sgml-mode-map (kbd "C-c e") 'sgml-insert-element)
     (define-key sgml-mode-map (kbd "C-c h") 'sgml-set-parent-document)))

;;;============================================================================
;;; HTML5-EL

(add-to-list 'load-path (concat shared-lisp-dir "/html5-el") t)

(eval-after-load
    "nxml-mode"
  '(require 'whattf-dt))

(eval-after-load
    "rng-loc"
  '(add-to-list 'rng-schema-locating-files
                (concat shared-lisp-dir "/html5-el/schemas.xml")))

;;;============================================================================
;;; HAML/SASS/SCSS MODE

(autoload 'haml-mode "haml-mode" "Major mode for editing Haml files." t)
(add-to-list 'auto-mode-alist '("\\.haml\\'" . haml-mode))

(eval-after-load
    "haml-mode"
  '(progn
     ;; HAML mode tries to set up "electric backspace" behavior, which I hate
     ;; because it doesn't support selecting a region, hitting backspace, and
     ;; having the region be deleted. The mode does not appear to provide any
     ;; built-in way of disabling this behavior, so I have to undefine the
     ;; keybinding in the mode's sparse keymap (the keybinding then falls back
     ;; to delete-backward-char).
     (define-key haml-mode-map (kbd "<backspace>") nil)
     (define-key haml-mode-map (kbd "DEL") nil)))

(autoload 'slim-mode "slim-mode" "Major mode for editing Slim files." t)
(add-to-list 'auto-mode-alist '("\\.slim\\'" . slim-mode))

(eval-after-load
    "slim-mode"
  '(progn
     ;; See note re Haml mode above. Same issue here.
     (define-key slim-mode-map (kbd "<backspace>") nil)
     (define-key slim-mode-map (kbd "DEL") nil)))

(autoload 'sass-mode "sass-mode" "Major mode for editing Sass files." t)
(add-to-list 'auto-mode-alist '("\\.sass\\'" . sass-mode))

(autoload 'scss-mode "scss-mode" "Major mode for editing SCSS files." t)
(add-to-list 'auto-mode-alist '("\\.scss\\'" . scss-mode))

(eval-after-load
    "scss-mode"
  '(progn
     ;; Don't need Emacs to autogenerate the compiled CSS files for me
     (setq scss-compile-at-save nil)))

;;;============================================================================
;;; MAGIT

(add-to-list 'load-path (concat shared-lisp-dir "/magit") t)
(autoload 'magit-status "magit" "Control Git from Emacs." t)

;;;============================================================================
;;; ZENCODING MODE

;; This minor mode is only useful when editing HTML markup; add it to the
;; relevant keymaps and autoload the mode the first time it's invoked.

(autoload 'zencoding-expand-line "zencoding-mode"
  "Unfold CSS-selector-like expressions to markup." t)

(setq zencoding-indentation 2)

(eval-after-load "nxml-mode"
  '(define-key nxml-mode-map (kbd "C-c C-l") 'zencoding-expand-line))

(eval-after-load "sgml-mode"
  '(define-key html-mode-map (kbd "C-c C-l") 'zencoding-expand-line))

;;;============================================================================
;;; MULTIPLE-MAJOR-MODES

(add-to-list 'load-path (concat shared-lisp-dir "/mmm") t)
(require 'mmm-auto nil t)

(setq
 mmm-global-mode 'maybe
 mmm-submode-decoration-level 2)

(eval-after-load
    "mmm-mode"
  '(progn
     (define-key mmm-mode-map (kbd "M-p") 'mmm-parse-buffer)
     (set-face-attribute 'mmm-default-submode-face nil
                         :background "unspecified-bg")
     (set-face-attribute 'mmm-code-submode-face nil
                         :background "unspecified-bg")))

(eval-after-load
    "mmm-auto"
  '(progn
     (mmm-add-group
      'html-plus
      '((javascript-block
         :front "<script[^>]*>"
         :back "</script>"
         :submode javascript-mode)
        (flex-actionscript-block
         :front "<mx:Script>"
         :back "</mx:Script>"
         :submode javascript-mode)
        (javascript-handler
         :front (concat
                 "on\\("
                 (mapconcat
                  'identity
                  '("blur" "change" "click" "dblclick" "focus" "keydown"
                    "keypress" "keyup" "load" "mousedown" "mousemove"
                    "mouseout" "mouseover" "mouseup" "reset" "select"
                    "submit" "unload") "\\|")
                 "\\)=\"")
         :back "\""
         :submode javascript-mode)
        (css-block
         :front "<style[^>]*>"
         :back "</style>"
         :submode css-mode)
        (css-inline
         :front "style=\""
         :back "\""
         :submode css-mode)
        (php-block
         :front "<[?]" ;; formerly "<[?]\\S-*"
         :back "[?]>"
         :submode php-mode)
        (ruby-block
         :front "<%[#=]?"
         :back "%>"
         :submode ruby-mode)))
     (add-to-list 'mmm-mode-ext-classes-alist '(sgml-mode nil html-plus))
     (add-to-list 'mmm-mode-ext-classes-alist '(xml-mode  nil html-plus))))

;;;============================================================================
;;; YAML

(autoload 'yaml-mode "yaml-mode" "Major mode for editing YAML files." t)
(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-mode))

;;;============================================================================
;;; MARKDOWN

(autoload 'markdown-mode "markdown-mode" "Major mode for Markdown files." t)
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(eval-after-load
    "markdown"
  '(progn
     (define-key markdown-mode-map (kbd "`") 'self-insert-command)))

;;;============================================================================
;;; EDIFF

(eval-after-load
    "ediff"
  '(progn
     (setq ediff-window-setup-function 'ediff-setup-windows-plain)))

;;;============================================================================
;;; ORG-MODE

;; Org-mode is distributed with Emacs as of version 22-point-something...
;; use it for *.org files if available, otherwise try outline-mode (from
;; which org-mode is derived)

(cond
 ((fboundp 'org-mode)
  (add-to-list 'auto-mode-alist '("\\.org\\'" . org-mode)))
 ((fboundp 'outline-mode)
  (add-to-list 'auto-mode-alist '("\\.org\\'" . outline-mode))))

;;;============================================================================
;;; CALENDAR

;; Normally, having scroll-margin set > 0 is nice (it keeps the cursor off the
;; top and bottom edges of the buffer), but Emacs' calendar is auto-sized to
;; the minimum possible number of lines, so it's counterproductive here.

(add-hook 'calendar-mode-hook
	  (lambda ()
	    (make-local-variable 'scroll-margin)
	    (setq scroll-margin 0)))

;;;============================================================================
;;; ISPELL

(setq
 ispell-program-name "aspell"
 ;; Get suggestions as fast as possible from aspell
 ispell-extra-args '("--sug-mode=ultra"))

;;;============================================================================
;;; COLOR THEMES

(add-to-list 'load-path (concat shared-lisp-dir "/color-theme") t)
(require 'color-theme-autoloads nil t)

;;;============================================================================
;;; UNIQUIFY

;; Same "require" strategy here as with yasnippet (q.v. above).
(add-hook 'find-file-hook
          (lambda () (require 'uniquify nil t)))

(eval-after-load
    "uniquify"
  '(progn
     (setq uniquify-buffer-name-style 'forward)))

;;;============================================================================
;;; CALENDAR SETTINGS

(setq
 calendar-latitude 42.73
 calendar-longitude -73.69
 calendar-location-name "Troy, NY"
 mark-holidays-in-calendar t
 calendar-holiday-marker 'font-lock-warning-face)

;;;============================================================================
;;; DEFT

(autoload 'deft "deft" "Quickly browse, filter, and edit plain text notes." t)
(setq
 deft-directory "~/Dropbox/simplenote")

;;;============================================================================
;;; COL-HIGHLIGHT

(add-to-list 'load-path (concat shared-lisp-dir "/col-highlight") t)
(autoload 'col-highlight-flash "col-highlight" "Highlight current column." t)

;;;============================================================================
;;; FIND-FILE-IN-PROJECT

(autoload 'find-file-in-project
  "find-file-in-project" "Find files in a project quickly." t)
(eval-after-load
    "find-file-in-project"
  '(progn
     (setq ffip-patterns
           (append ffip-patterns
                   '("*.haml" "*.sass" "*.erb")))))
